import { Element, Group, ZRenderType, init } from 'zrender'

export class CoordinateSystem {
  readonly zr: ZRenderType
  readonly root = new Group()

  get width() {
    return this.zr.getWidth()!
  }

  get height() {
    return this.zr.getHeight()!
  }

  get center() {
    const { root, width, height } = this
    return root.transformCoordToLocal(width / 2, height / 2)
  }

  set center(val) {
    const { width, height, root } = this
    const scale = root.scaleX

    root.attr({
      x: width / 2 - val[0] * scale,
      y: val[1] * scale + height / 2,
      scaleX: scale,
      scaleY: -scale
    })
  }

  get scale() {
    return this.root.scaleX
  }

  set scale(val) {
    const { width, height, root } = this
    const x = (width / 2 - root.x) / root.scaleX
    const y = (height / 2 - root.y) / root.scaleY

    root.attr({
      x: width / 2 - x * val,
      y: y * val + height / 2,
      scaleX: val,
      scaleY: -val
    })
  }

  constructor(div: HTMLDivElement) {
    this.zr = init(div, {
      devicePixelRatio: devicePixelRatio
    })
    const { zr, root, width, height } = this

    root.attr({
      x: width / 2,
      y: height / 2,
      scaleX: 10,
      scaleY: -10
    })

    zr.add(root)


    let mousedownAt: number[] | undefined

    zr.on('mousedown', (e) => {
      mousedownAt = [e.offsetX, e.offsetY]
    })

    zr.on('mousemove', (e) => {
      if (mousedownAt) {
        this.root.attr({
          x: this.root.x + e.offsetX - mousedownAt[0],
          y: this.root.y + e.offsetY - mousedownAt[1],
        })
        mousedownAt = [e.offsetX, e.offsetY]
      }
    })

    zr.on('mouseup', () => {
      mousedownAt = undefined
    })

    zr.on('mousewheel', (e) => {
      const delta = e.wheelDelta * 0.1
      const scale = Math.pow(2, delta)
      this.root.attr({
        x: e.offsetX + (this.root.x - e.offsetX) * scale,
        y: e.offsetY + (this.root.y - e.offsetY) * scale,
        scaleX: this.root.scaleX * scale,
        scaleY: this.root.scaleY * scale,
      })
    })


  }

  zoomTo(target: Element, percent = 0.8) {
    const { width, height, root } = this

    const rect = target.getBoundingRect()
    const scale = Math.min(width * percent / rect.width, height * percent / rect.height)
    root.attr({
      x: width / 2 - (rect.x + rect.width / 2) * scale,
      y: (rect.y + rect.height / 2) * scale + height / 2,
      scaleX: scale,
      scaleY: -scale
    })
  }

  destroy() {
    this.zr.dispose()
  }
}